﻿using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System.Drawing;
using System.IO;
namespace Hr.Orc.Client.Helper
{
    public class CheckImageHelper
    {
        public static string GetImgPath(Stream imgStream, string directory, string fileName) {
			Bitmap bmp = new Bitmap(imgStream);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
			}
			Bitmap bmp2 = new Bitmap(bmp, bmp.Width, bmp.Height);
			Graphics draw = Graphics.FromImage(bmp2);
			draw.DrawImage(bmp, 0, 0);
			draw.Dispose();
			string imagePath = Path.Combine(directory, $"img_{fileName}.png");
			bmp2.Save(imagePath);
            return imagePath;
		}
       
        public static bool CheckHasStamp(string imagePath,string directoryPath, string attachmentId)
        {// 过滤图像
            var filterpath = ImgFilterColor(imagePath, directoryPath, $"{attachmentId}_filter");
            bool hasStamp = false;
            // 加载图像
            Image<Bgr, Byte> img = new Image<Bgr, byte>(filterpath);
            // 灰度化
            Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp();
			if (!Directory.Exists(directoryPath))
			{
				// 创建目录
				Directory.CreateDirectory(directoryPath);
			}
            // 边缘检测
            Image<Gray, Byte> cannyEdges = gray.Canny(120, 120, 3, false);
            // 找到轮廓
            using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
            {
                CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
                // 遍历轮廓
                for (int i = 0; i < contours.Size; i++)
                {
                    VectorOfPoint contour = contours[i];
                    Rectangle rect = CvInvoke.BoundingRectangle(contour);
                    // 可以通过rect的大小和位置来判断是否是印章
                    if (rect.Width > 150 && rect.Height > 150)
                    {
                        hasStamp = true;
                        // 可以在原图上画出这个区域，标记印章
                        CvInvoke.Rectangle(img, rect, new Bgr(Color.Red).MCvScalar, 2);
                    }
                }
                string DetectStampPath = Path.Combine(directoryPath, $"{attachmentId}.png");
                img.Save(DetectStampPath);
                gray.Dispose();
                img.Dispose();
            }
            return hasStamp;
        }

        /// <summary>
        /// 过滤只剩红色
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="directoryPath"></param>
        /// <param name="attachmentId"></param>
        /// <returns></returns>
        public static string ImgFilterColor(string  imagePath, string directoryPath, string attachmentId)
        {
            Mat srcMat = new Mat(imagePath);
            Mat hsvMat = new Mat();
            Mat maskMat = new Mat();
            Mat tempMat = srcMat.Clone();
            CvInvoke.CvtColor(tempMat, hsvMat, ColorConversion.Bgr2Hsv);
            Mat[] channels = hsvMat.Split();
            MCvScalar redMin1 = new MCvScalar(0, 43, 46); // 第一个红色范围的下限
            MCvScalar redMax1 = new MCvScalar(10, 255, 255); // 第一个红色范围的上限
            MCvScalar redMin2 = new MCvScalar(156, 43, 46); // 第二个红色范围的下限
            MCvScalar redMax2 = new MCvScalar(180, 255, 255);// 第二个红色范围的上限
            Mat mask1 = new Mat();
            Mat mask2 = new Mat();
            CvInvoke.InRange(hsvMat, new ScalarArray(redMin1), new ScalarArray(redMax1), mask1);
            CvInvoke.InRange(hsvMat, new ScalarArray(redMin2), new ScalarArray(redMax2), mask2);
            Mat mask = new Mat();
            CvInvoke.BitwiseOr(mask2, mask1, maskMat );
            // 提取红色区域并拷贝到黑底的图片上
            Mat black = Mat.Ones(srcMat.Rows, srcMat.Cols, DepthType.Cv8U, 3);
            tempMat.CopyTo(black, maskMat);
			if (!Directory.Exists(directoryPath))
			{
				// 创建目录
				Directory.CreateDirectory(directoryPath);
			}
			string FilterPath = Path.Combine(directoryPath, $"{attachmentId}_Filter.png");
            black.Save(FilterPath);
            return FilterPath;
        }
        /// <summary>
        /// 印章检测(结合颜色过滤)
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="directoryPath"></param>
        /// <param name="attachmentId"></param>
        public static bool DetectSeal(string imagePath,  string directoryPath, string attachmentId)
        {
            Image<Bgr, byte> originalImage = new Image<Bgr, byte>(imagePath);
            
            var widthRatio = originalImage.Width / 1400M;
            if (originalImage.Height < 1400 || originalImage.Width < 1000) {
                widthRatio = 1;
            }
            // 转为灰度
            Image<Gray, byte> grayImage = originalImage.Convert<Gray, byte>();
          /*  string detectSealPath1 = Path.Combine(directoryPath, $"{attachmentId}_DetectSealPath1.png");
            grayImage.Save(detectSealPath1);*/
            // 图片高适
            Image<Gray, byte> blurredImage = grayImage.SmoothGaussian(1);
            string detectSealPath2 = Path.Combine(directoryPath, $"{attachmentId}_DetectSealPath2.png");
            blurredImage.Save(detectSealPath2);
            // Step 4: Perform edge detection
            /*Image<Gray, byte> edges = blurredImage.Canny(30, 150);*/
            Image<Gray, byte> edges = blurredImage.Canny(60, 150, 3, false);
            string detectSealPath3 = Path.Combine(directoryPath, $"{attachmentId}_DetectSealPath3.png");
            edges.Save(detectSealPath3);
            // Step 5: Define parameters for Hough circle transform
            double minDist =Convert.ToInt32(120* widthRatio); // 圆中心最小距离
            double dp = 1.1;        // 值越小检测越精确
            double param1 = 50;   // 边缘检测器上限阈值
            double param2 = 100;   // 值越小，假圆越多
            int minRadius = Convert.ToInt32(60 * widthRatio);   // 最小半径
            int maxRadius = Convert.ToInt32(300 * widthRatio);  // 最大半径

            // Detect circles using Hough transform
            CircleF[] circles = CvInvoke.HoughCircles(edges, HoughModes.Gradient, dp, minDist, param1, param2, minRadius, maxRadius);
            // Step 6: Draw circles on the original image
            foreach (CircleF circle in circles)
            {
                Console.WriteLine($"{circle.Center.X},{circle.Center.Y},{circle.Radius}");
                CvInvoke.Circle(originalImage,new System.Drawing.Point(Convert.ToInt32(circle.Center.X), Convert.ToInt32(circle.Center.Y)), (int)circle.Radius, new Bgr(Color.Red).MCvScalar, 2);

                //CvInvoke.Circle(originalImage, new System.Drawing.Point(Convert.ToInt32(circle.Center.X), Convert.ToInt32(circle.Center.Y)), 50, new Bgr(Color.Red).MCvScalar, 2);
                //CvInvoke.Circle(originalImage, new System.Drawing.Point(Convert.ToInt32(circle.Center.X), Convert.ToInt32(circle.Center.Y)), 300, new Bgr(Color.Red).MCvScalar, 2);
            }
            string detectSealPath = Path.Combine(directoryPath, $"{attachmentId}_DetectSealPath.png");
            originalImage.Save(detectSealPath);
            return circles.Length > 0;


		}

        /// <summary>
        /// 模板匹配(不适用)
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="templatePath"></param>
        /// <param name="directoryPath"></param>
        /// <param name="attachmentId"></param>
        public static void FindSeal(string imagePath, string templatePath, string directoryPath, string attachmentId)
        {
            Image<Bgr, byte> originalImage = new Image<Bgr, byte>(imagePath);
            Image<Bgr, byte> templateImage = new Image<Bgr, byte>(templatePath);
            //转为灰度
            Image<Gray, byte> grayOriginalImage = originalImage.Convert<Gray, byte>();
            Image<Gray, byte> grayTemplateImage = templateImage.Convert<Gray, byte>();
            string templateImgPath = Path.Combine(directoryPath, $"{attachmentId}_Template.png");
            grayTemplateImage.Save(templateImgPath);
            string originalImgPath = Path.Combine(directoryPath, $"{attachmentId}_original.png");
            grayOriginalImage.Save(originalImgPath);

            // 根据模板匹配
            Image<Gray, float> result = grayOriginalImage.MatchTemplate(grayTemplateImage, TemplateMatchingType.CcoeffNormed);
            // 设置阈值
            double threshold = 0.2;
            List<Rectangle> matches = new List<Rectangle>();
            for (int y = 0; y < result.Height; y++)
            {
                for (int x = 0; x < result.Width; x++)
                {
                    if (result.Data[y, x, 0] > threshold)
                    {
                        matches.Add(new Rectangle(x, y, grayTemplateImage.Width, grayTemplateImage.Height));
                    }
                }
            }
            // 查找匹配位置
           /* Rectangle[] matches = result.FindThreshold(threshold);*/

            // 在原始图像上画出检测到的圆形
            foreach (Rectangle match in matches)
            {
                CvInvoke.Rectangle(originalImage, match, new Bgr(Color.Red).MCvScalar, 2);
            }


          /*  // Find the maximum value in the result image
            double[] minVal, maxVal;
            System.Drawing.Point[] minLoc, maxLoc;
            result.MinMax(out minVal, out maxVal, out minLoc, out maxLoc);

            // Draw a rectangle around the matched area
            Rectangle rect = new Rectangle(maxLoc[0], grayTemplateImage.Size);
            CvInvoke.Rectangle(originalImage, rect, new Bgr(Color.Red).MCvScalar, 2);*/

            // Save the result image
            string FilterPath = Path.Combine(directoryPath, $"{attachmentId}_FindSeal.png");
            originalImage.Save(FilterPath);
        }
        public static Image<Bgr, Byte> CropImage(Image<Bgr, Byte> sourceImage, Rectangle cropRect)
        {
            int width = sourceImage.Width;
            int height = sourceImage.Height;
            // 设置ROI区域
            sourceImage.ROI = cropRect;
            // 创建一个新图像来保存裁剪结果
            Image<Bgr, Byte> croppedImage = new Image<Bgr, Byte>(cropRect.Width, cropRect.Height);
            // 将裁剪区域的内容拷贝到新图像
            sourceImage.CopyTo(croppedImage);
            // 重置ROI区域
            sourceImage.ROI = new Rectangle(0, 0, width, height);
            return croppedImage;
        }

    }
}
